#include "Task.hpp"
//#include <iostream>
//#include <vector>
#include <string>
#include <cstdlib>
#include <cassert>
#include <ctime>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

const int processnum = 10;
std::vector<task_t> tasks;

// 先描述
class channel
{
public:
    channel (int cmdfd,pid_t slaverid,const std::string& processname)
    :_cmdfd(cmdfd),_slaverid(slaverid),_processname(processname)
    {}
public:
    int _cmdfd;                 //发送任务的文件描述符
    pid_t _slaverid;            //子进程的id
    std::string _processname;   //子进程的名字
};

void slaver()
{
    while(true)
    {
        int cmdcode = 0;
        int n = read(0,&cmdcode,sizeof(int));
        //std::cout<<n<<std::endl;
        if(n == sizeof(int))
        {
            //执行cmdcode对应的任务列表
            std::cout <<"slaver say@ get a command: "<< getpid() << " : cmdcode: " <<  cmdcode << std::endl;
            if(cmdcode >=0 && cmdcode < tasks.size())    tasks[cmdcode]();
        }
        if(n <= 0) break;
    }
}

void InitProcessPool(std::vector<channel>& channels)
{
    // version 2: 确保每一个子进程都只有一个写端
    std::vector<int> oldfds;
    for(int i=0;i<processnum;i++)
    {
        int pipefd[2];  //临时空间
        int n = pipe(pipefd);
        assert(!n); //检测是否出错

        pid_t id = fork();
        if(id == 0) //child
        {
            std::cout << "child: " << getpid() << " close history fd: ";
            for(auto fd : oldfds) {
                std::cout << fd << " ";
                close(fd);
            }
            std::cout << "\n";

            close(pipefd[1]);
            dup2(pipefd[0],0);  //重定向为写文件可以减少传参
            close(pipefd[0]);
            // slaver(pipefd[0]);
            slaver();
            std::cout << "process : " << getpid() << " quit" << std::endl;

            exit(0);
        }
        //father
        close(pipefd[0]);
        std::string name = "process-"+std::to_string(i);
        channels.push_back(channel(pipefd[1],id,name));
        oldfds.push_back(pipefd[1]);
    }
}

void Debug(const std::vector<channel>& channels)
{
    for(const auto &c : channels)
    {
         std::cout << c._cmdfd << " " << c._slaverid << " " << c._processname << std::endl;
    }
}

void menu()
{
    std::cout << "################################################" << std::endl;
    std::cout << "# 1. 刷新日志             2. 刷新出来野怪       #" << std::endl;
    std::cout << "# 3. 检测软件是否更新      4. 更新用的血量和蓝量 #" << std::endl;
    std::cout << "#                         0. 退出              #" << std::endl;
    std::cout << "################################################" << std::endl;
}

void ctrlSlaver(const std::vector<channel>& channels)
{
    int which = 0;  //轮转
    //int cnt=5;
    while(true)
    {
        sleep(1);
        int select=0;
        menu();
        std::cout << "Please Enter@ ";
        std::cin>>select;

        if(select <= 0 || select >= 5)  break;
        //1.选择任务
        // int cmdcode = rand()%tasks.size();    //随机法
        int cmdcode = select-1;

        //2.选择进程
        // int process = rand()%channels.size();
        
        std::cout << "father say: " << " cmdcode: " <<
            cmdcode << " already sendto " << channels[which]._slaverid << " process name: " 
                << channels[which]._processname << std::endl;
        //3.发送任务
        write(channels[which]._cmdfd,&cmdcode,sizeof(int));
        // write(process,&cmdcode,sizeof(int));

        which++;
        which %= channels.size();
    }
}

void QuitProcess(const std::vector<channel>& channels)
{
    for(const auto& c : channels)
    {
        close(c._cmdfd);
        waitpid(c._slaverid,nullptr,0);
    }
    
    // version1 
    // int last = channels.size()-1;
    // for(int i = last; i >= 0; i--)
    // {
    //     close(channels[i]._cmdfd);
    //     waitpid(channels[i]._slaverid, nullptr, 0);
    // }

    // for(const auto &c : channels) close(c._cmdfd);
    // // sleep(5);
    // for(const auto &c : channels) waitpid(c._slaverid, nullptr, 0);
    // // sleep(5);
}

int main()
{
    LoadTask(tasks);

    srand(time(nullptr)^1023);
    //在组织
    std::vector<channel> channels; 
    //1.初始化
    InitProcessPool(channels);
    //Debug(channels);

    //2.开始控制子进程
    ctrlSlaver(channels);

    //3.清理收尾
    QuitProcess(channels);

    return 0;
}
